/**
 * ConnectFilter.java<br>
 *
 *
 * @version 下午8:07:21
 */
package com.iwechat.adapter.mina.filter;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

import javax.annotation.PostConstruct;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.mina.core.filterchain.IoFilterAdapter;
import org.apache.mina.core.session.IoSession;
import org.springframework.beans.factory.annotation.Autowired;

import com.iwechat.adapter.mina.entity.Connect;
import com.iwechat.adapter.mina.entity.ConnectResp;
import com.iwechat.adapter.mina.entity.PDU;
import com.iwechat.emuns.ConstEmus;
import com.iwechat.service.ClientFactory;

/**
 * 控制每个IP最大连接数的过滤器<br>
 * 仅在developmentMode=false时严格实行,否则允许每个IP至少一个连接
 *
 *
 */
public class ConnectFilter extends IoFilterAdapter {

	private static final Logger		logger			= LogManager.getLogger();

	@Autowired
	ClientFactory					cfactory;

	private boolean					developmentMode;
	private Map<String, Integer>	currentConnMap	= new ConcurrentHashMap<String, Integer>();
	private ReentrantLock			connLock		= new ReentrantLock();

	@Override
	public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
		// connect 消息
		if (message instanceof Connect) {
			// 设置session
			String clientId = ((Connect) message).getClientID().trim();
			if (!session.containsAttribute(ConstEmus.clientId.value())) {
				session.setAttribute(ConstEmus.clientId.value(), clientId);
			}

			int max = cfactory.getMaxConnByClientId(clientId);
			// 开发模式默认一个链接
			if (max == 0 && developmentMode) {
				max = 1;
			}

			if (max > 0 && connLock.tryLock()) {
				try {
					// 当前连接数
					int lastConnNum = 0;
					if (currentConnMap.containsKey(clientId)) {
						try {
							lastConnNum = currentConnMap.get(clientId).intValue();
						} catch (NullPointerException e) {
							lastConnNum = 0;
						}
					}

					if (lastConnNum < max) {
						nextFilter.messageReceived(session, message);
					} else {
						// 发送登录失败响应
						ConnectResp resp = new ConnectResp((Connect) message, PDU.ERRORCODE_CONN_TOO_MANY);
						session.write(resp);
						logger.error("clientId [{}] 已达最大连接数 [{}] ", clientId, max);
					}
					// seesion即使将要close了这里也应该累加
					currentConnMap.put(clientId, ++lastConnNum);
				} finally {
					connLock.unlock();
				}
			} else {
				session.closeNow();
				logger.error("非法clientId [{}] ,请检查表CLIENT_CONFIGS确认.", clientId);
			}
		} else {
			super.messageReceived(nextFilter, session, message);
		}
	}

	@Override
	public void sessionClosed(NextFilter nextFilter, IoSession session) throws Exception {
		if (session.containsAttribute(ConstEmus.clientId.value())) {
			String clientId = (String) session.getAttribute(ConstEmus.clientId.value());
			if (connLock.tryLock()) {
				try {
					// 当前连接数
					int lastConnNum = 0;
					if (currentConnMap.containsKey(clientId)) {
						try {
							lastConnNum = currentConnMap.get(clientId).intValue();
						} catch (NullPointerException e) {
							lastConnNum = 0;
						}
					}
					lastConnNum--;
					if (lastConnNum < 0) {
						lastConnNum = 0;
					}
					currentConnMap.put(clientId, lastConnNum);
				} finally {
					connLock.unlock();
				}
			}
		}
		super.sessionClosed(nextFilter, session);
	}

	public void setDevelopmentMode(boolean developmentMode) {
		this.developmentMode = developmentMode;
	}

	@Override
	@PostConstruct
	public void init() {
		logger.info("### " + this + "@" + this.hashCode() + " init succeed!");
	}

}
